﻿using OneOf.Types;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Tensorflow;
using Tensorflow.Util;


namespace OpenCvApplication.View
{
    public partial class FrmSearchImages : Form
    {
        public FrmSearchImages()
        {
            InitializeComponent();
            foreach (Control item in panel2.Controls)
            {
                if (item is PictureBox pb)
                {
                    pb.Click += Pb_Click;
                }
            }
        }

        private void Pb_Click(object? sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            const string filter = "Image Files (*.jpg, *.jpeg, *.png, *.gif, *.bmp)|*.jpg; *.jpeg; *.png; *.gif; *.bmp";
            openFileDialog.Filter = filter;
            openFileDialog.Title = "Select an Image File";

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                string selectedImagePath = openFileDialog.FileName;
                PictureBox pictureBox = sender as PictureBox;
                if (pictureBox.Image != null)
                    pictureBox.Dispose();
                pictureBox.Image = Image.FromFile(selectedImagePath);
                pictureBox.Tag = selectedImagePath;
            }
            openFileDialog.Dispose();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string path = pictureBox1.Tag.ToString();

            if (pictureBox2.Image != null)
            {
                pictureBox2.Image.Dispose();
            }
            Stopwatch stopwatch = Stopwatch.StartNew();
            pictureBox2.Image = ToBitmap(path);
            stopwatch.Stop();
            Trace.WriteLine($"耗时：{stopwatch.ElapsedMilliseconds}ms");

            if (pictureBox3.Image != null)
            {
                pictureBox3.Image.Dispose();
            }

            stopwatch = Stopwatch.StartNew();
            pictureBox3.Image = ToBitmap2(path);
            stopwatch.Stop();
            Trace.WriteLine($"耗时：{stopwatch.ElapsedMilliseconds}ms");
        }
        unsafe Bitmap ToBitmap(string path)
        {
            Bitmap bmp = new Bitmap(path);
            Rectangle rectangle = new Rectangle(0, 0, bmp.Width, bmp.Height);
            BitmapData bitmapData = bmp.LockBits(rectangle, ImageLockMode.ReadWrite, bmp.PixelFormat);
            byte* ptr = (byte*)bitmapData.Scan0;
            byte temp = 0;
            int str = bitmapData.Stride - bitmapData.Width * 3;
            for (int y = 0; y < bitmapData.Height; y++)
            {
                for (int x = 0; x < bitmapData.Width; x++)
                {
                    temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);
                    ptr[0] = ptr[1] = ptr[2] = temp;
                    ptr += 3;
                }
                // 指向下一行数组的首个字符
                ptr += str;
            }
            bmp.UnlockBits(bitmapData);
            return bmp;
        }
        Bitmap ToBitmap2(string path)
        {
            Bitmap bmp = new Bitmap(path);
            Rectangle rectangle = new Rectangle(0, 0, bmp.Width, bmp.Height);
            BitmapData bitmapData = bmp.LockBits(rectangle, ImageLockMode.ReadWrite, bmp.PixelFormat);
            var ptr = bitmapData.Scan0;
            int bytes = bitmapData.Stride * bitmapData.Height;
            byte[] rgbValues = new byte[bytes];
            Marshal.Copy(ptr, rgbValues, 0, bytes);
            byte temp = 0;
            int sr;
            int str = bitmapData.Stride - bitmapData.Width * 3;
            for (int y = 0; y < bmp.Height; y++)
            {
                for (int x = 0; x < bitmapData.Width * 3; x += 3)
                {
                    sr = y * bitmapData.Stride;
                    temp = (byte)(0.299 * rgbValues[sr + 2 + x] + 0.587 * rgbValues[sr + 1 + x] + 0.114 * rgbValues[sr + 0 + x]);
                    rgbValues[sr + 0 + x] = rgbValues[sr + 1 + x] = rgbValues[sr + 2 + x] = temp;
                }
                // 指向下一行数组的首个字符
                ptr += str;
            }
            Marshal.Copy(rgbValues, 0, ptr, bytes);
            bmp.UnlockBits(bitmapData);
            return bmp;
        }
        //void Load(string source,string target)
        //{
        //    // 载入模型
        //    var model = ResNet.LoadResNet50();
        //    // 加载图像
        //    var image1 = ImageUtil.LoadTensorFromImageFile(source);
        //    var image2 = ImageUtil.LoadTensorFromImageFile(target);

        //    // 提取特征
        //    var feature1 = ExtractFeatures(image1, model);
        //    var feature2 = ExtractFeatures(image2, model);

        //    // 计算相似度
        //    var similarityScore = CalculateSimilarity(feature1, feature2);
        //    Console.WriteLine("图片相似度： " + similarityScore);
        //}
        //Tensor ExtractFeatures(Tensor image, ResNet50 model)
        //{
        //    // 预处理图像
        //    var processedImage = ImageUtil.ResizeAndCropCenter(image, model.InputHeight, model.InputWidth);
        //    processedImage = ImageUtil.Normalize(image, mean: model.Mean, std: model.Std);
        //    // 转换图像形状以匹配模型输入
        //    var reshapedImage = processedImage.Reshape(new long[] { 1, model.InputHeight, model.InputWidth, 3 });

        //    // 获取特征
        //    var features = model.Predict(reshapedImage);

        //    return features;
        //}
        //double CalculateSimilarity(TFTensor feature1, TFTensor feature2)
        //{
        //    // 使用余弦相似度计算特征之间的相似度
        //    var similarity = CosineSimilarity(feature1.ToArray<float>(), feature2.ToArray<float>());
        //    return similarity;
        //}

        double CosineSimilarity(float[] vector1, float[] vector2)
        {
            int vectorSize = Vector<float>.Count;
            double dotProduct = 0.0;
            double magnitude1 = 0.0;
            double magnitude2 = 0.0;
            int j = 0;
            for (; j < vector1.Length - vectorSize; j += vectorSize)
            {
                var v1 = new Vector<float>(vector1, j);
                var v2 = new Vector<float>(vector2, j);
                dotProduct += Vector.Dot(v1, v2);
                magnitude1 += Vector.Dot(v1, v1);
                magnitude2 += Vector.Dot(v2, v2);
            }
            for (; j < vector1.Length; j++)
            {
                dotProduct += vector1[j] * vector2[j];
                magnitude1 += vector1[j] * vector1[j];
                magnitude2 += vector2[j] * vector2[j];
            }
            magnitude1 = Math.Sqrt(magnitude1);
            magnitude2 = Math.Sqrt(magnitude2);
            return dotProduct / (magnitude1 * magnitude2);
        }
    }
}
